﻿#include "../../../includes/database/tsdb/ctimeseriesdb.h"
#include "../../../includes/QsLog/QsLog.h"
#include "../../../includes/common/NedAllocatorImpl.h"

#if defined (WIN32)
CTimeSeriesDB::CTimeSeriesDB(QObject *parent)
    : QObject(parent),
      m_dbp(NULL),
      dbp_ret(-1),
      m_dbisOpened(false),
      m_isEnableSync(true)
{
    if ((dbp_ret = db_create(&m_dbp, NULL, 0)) != 0)
    {
        QLOG_INFO()<<"db_create:"<<db_strerror(dbp_ret);
        emit on_signalLog(QString("db_create:")+db_strerror(dbp_ret));
    }

    // 30秒刷新缓存到硬盘
    QObject::connect(&m_updateTimer,
                     &QTimer::timeout,
                     this,
                     &CTimeSeriesDB::tsdb_pdate);

    if(m_isEnableSync)
        m_updateTimer.start(30000);
}

CTimeSeriesDB::~CTimeSeriesDB()
{
    if(m_dbp)
    {
        if((dbp_ret = m_dbp->close(m_dbp, 0)) != 0)
            QLOG_ERROR()<<"db_close:"<<db_strerror(dbp_ret);
    }
}

/**
 * @brief CTimeSeriesDB::openDB 打开指定数据库文件
 * @param dbpath
 * @return
 */
bool CTimeSeriesDB::openDB(QString dbpath)
{
    if(dbpath.isEmpty() || m_dbp == NULL || m_dbisOpened)
        return false;

    if ((dbp_ret = m_dbp->open(m_dbp,
            NULL,
            dbpath.toStdString().c_str(),
            NULL,
            DB_BTREE,
            DB_CREATE,
            0664)) != 0)
    {
        QLOG_ERROR()<<"db_open:"<<db_strerror(dbp_ret);
        emit on_signalLog(QString("db_open:")+db_strerror(dbp_ret));
        return false;
    }

    m_dbisOpened = true;

    return true;
}

/**
 * @brief CTimeSeriesDB::setEnableSync 设置是否定时刷新到数据库
 * @param isenable
 * @param msec
 */
void CTimeSeriesDB::setEnableSync(bool isenable,int msec)
{
    m_isEnableSync = isenable;

    if(m_isEnableSync)
        m_updateTimer.start(msec);
    else
        m_updateTimer.stop();
}

/**
 * @brief CTimeSeriesDB::putData 插入或者改变数据
 * @param key
 * @param data
 * @return
 */
bool CTimeSeriesDB::putData(QString key,QString data)
{
    if(key.isEmpty() ||
       data.isEmpty() ||
       m_dbp == NULL)
        return false;

    QMutexLocker locker(&m_msdblock);

    bool isReturn = true;
    DBT dbt_key, dbt_data;

    memset(&dbt_key, 0, sizeof(dbt_key));
    memset(&dbt_data, 0, sizeof(dbt_data));

    char *tempKey = (char*)allocBytes(key.toUtf8().size());
    memcpy(tempKey,key.toUtf8().data(),key.toUtf8().size());

    char *tempData = (char*)allocBytes(data.toUtf8().size());
    memcpy(tempData,data.toUtf8().data(),data.toUtf8().size());

    dbt_key.data = (void*)tempKey;
    dbt_key.size = key.toUtf8().size();
    dbt_data.data = (void*)tempData;
    dbt_data.size = data.toUtf8().size();

    if ((dbp_ret = m_dbp->put(m_dbp, NULL, &dbt_key, &dbt_data, 0)) != 0)
    {
        QLOG_ERROR()<<"db_put:"<<db_strerror(dbp_ret);
        emit on_signalLog(QString("db_put:")+db_strerror(dbp_ret));
        isReturn = false;
    }

    deallocBytes(tempKey);
    deallocBytes(tempData);

    return isReturn;
}

/**
 * @brief CTimeSeriesDB::getData 得到数据
 * @param key
 * @param data
 * @return
 */
bool CTimeSeriesDB::getData(QString key,QString& data)
{
    if(m_dbp == NULL)
        return false;

    QMutexLocker locker(&m_msdblock);

    bool isReturn = true;
    DBT dbt_key, dbt_data;

    memset(&dbt_key, 0, sizeof(dbt_key));
    memset(&dbt_data, 0, sizeof(dbt_data));

    char *tempKey = (char*)allocBytes(key.toUtf8().size());
    memcpy(tempKey,key.toUtf8().data(),key.toUtf8().size());

    dbt_key.data = (void*)tempKey;
    dbt_key.size = key.toUtf8().size();

    if ((dbp_ret = m_dbp->get(m_dbp, NULL, &dbt_key, &dbt_data, 0)) != 0)
    {
        QLOG_ERROR()<<"db_put:"<<db_strerror(dbp_ret);
        emit on_signalLog(QString("db_put:")+db_strerror(dbp_ret));
        isReturn = false;
    }

    deallocBytes(tempKey);

    data = QString::fromUtf8((const char*)dbt_data.data,dbt_data.size);

    //free(dbt_data.data);

    return isReturn;
}

void CTimeSeriesDB::tsdb_pdate()
{
    sync();
}

/**
 * @brief CTimeSeriesDB::sync 刷新缓存到硬盘
 */
void CTimeSeriesDB::sync(void)
{
    if(m_dbp == NULL)
        return;

    QMutexLocker locker(&m_msdblock);

    m_dbp->sync(m_dbp,0);
}

#endif
